﻿using System;
using System.Linq;
using System.Net;
using System.IO;
using System.Text;
using System.Windows;
using System.Windows.Browser;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Microsoft.Practices.Prism.Regions;
using Microsoft.Practices.Prism.Events;
using Microsoft.Practices.Prism.Commands;
using Microsoft.Practices.Unity;
using DXTools.Core;
using DXTools.UI.Core;
using DXTools.UI.Modules.ODataQueryDesigner.Views;
using DXTools.UI.Core.Events;
using DXTools.UI.Modules.ODataQueryDesigner.Model;
using DXTools.UI.Modules.ODataQueryDesigner.DataProviders;
using DXTools.UI.Core.ViewModel;
using DXTools.Core.CrmSdk;
using System.Collections.ObjectModel;

namespace DXTools.UI.Modules.ODataQueryDesigner.ViewModels
{
    public class DesignerViewModel : ViewModelBase
    {


        #region Properties

        private IDataProvider _dataProvider = null;
        private const string HEADER_INFO = "Designer";

        public DelegateCommand<object> GenerateCommand { get; private set; }
        public DelegateCommand<object> ExecuteCommand { get; private set; }
        public DelegateCommand<object> OpenBrowserCommand { get; private set; }
        public DelegateCommand<object> AddGroupANDCommand { get; private set; }
        public DelegateCommand<object> AddGroupORCommand { get; private set; }


        private ObservableCollection<EntityClass> _entities;
        private EntityClass _entity;
        private EntityClass _selectedEntity;
        private RelationshipClass _selectedOneToManyRelationship;
        private RelationshipClass _selectedManyToOneRelationship;
        private RelationshipClass _selectedManyToManyRelationship;

        private AttributeClass _selectedSortBy1Attribute;
        private AttributeClass _selectedSortBy2Attribute;
        private SortDirection _sortBy1Direction;
        private SortDirection _sortBy2Direction;


        #region ODataQuery properties

        private String _ODataQuery = String.Empty;
        private String _ODataQueryWithVariables = String.Empty;
        public String ResultXml { get; set; }
        public StringBuilder JSONResultXml { get; set; }
        public StringBuilder ATOMResultXml { get; set; }
        public StringBuilder CodeGeneratorScript { get; set; }
        private int? _skipNext;
        private int? _top;
        public string QueryLength { get; set; }


        #endregion


        #endregion

        public DesignerViewModel(IRegionManager regionManager, IEventAggregator eventAggregator, IUnityContainer container)
            : base(regionManager, eventAggregator, container)
        {
            this.HeaderInfo = HEADER_INFO;

            this.CloseViewCommand = new DelegateCommand<object>(this.CloseView, this.CanCloseView);
            this.GenerateCommand = new DelegateCommand<object>(this.Generate, this.CanGenerate);
            this.ExecuteCommand = new DelegateCommand<object>(this.Execute, this.CanExecute);
            this.OpenBrowserCommand = new DelegateCommand<object>(this.OpenBrowserWithQuery, this.CanOpenBrowser);
            this.AddGroupANDCommand = new DelegateCommand<object>(this.AddGroupAND, this.CanAddGroupAND);
            this.AddGroupORCommand = new DelegateCommand<object>(this.AddGroupOR, this.CanAddGroupOR);



            _dataProvider = new CRMDataProvider();

            ATOMResultXml = new StringBuilder();
            JSONResultXml = new StringBuilder();
            CodeGeneratorScript = new StringBuilder();

            _entities = new ObservableCollection<EntityClass>();
            _entity = new EntityClass();


            AsyncCallback asyncCallback = new AsyncCallback(result =>
            {

                IOrganizationService service = (IOrganizationService)result.AsyncState;
                ObservableCollection<EntityMetadata> data = (ObservableCollection<EntityMetadata>)service.EndExecute(result).Results[0].Value;

                Action method = () =>
                {
                    var entities = from a in data
                                   orderby a.SchemaName
                                   select new { SchemaName = a.SchemaName, LogicalName = a.LogicalName };

                    foreach (var entity in entities)
                    {
                        _entities.Add(new EntityClass(entity.SchemaName + "Set", entity.LogicalName));
                    }

                    this.IsBusy = false;

                };

                this.View.Dispatcher.BeginInvoke(method);

            });

            this.IsBusy = true;
            _dataProvider.RetrieveEntities(asyncCallback);


        }

        private void CloseView(object commandArg)
        {
            base.CloseView();
        }

        private bool CanCloseView(object commandArg)
        {
            return true;
        }

        private bool CanGenerate(object commandArg)
        {
            return (SelectedEntity != null); ;
        }

        private bool CanExecute(object commandArg)
        {
            bool isAllowedToExecuteREST = false;

            // Validate OData
            if (_ODataQuery.Length == 0 | _ODataQuery.Length > 2048)
            {
                isAllowedToExecuteREST = false;
            }
            else
            {
                isAllowedToExecuteREST = true;
            }

            return isAllowedToExecuteREST;
        }

        private bool CanOpenBrowser(object commandArg)
        {
            bool isAllowedToOpenBrowser = false;

            // Validate OData
            if (_ODataQuery.Length == 0 | _ODataQuery.Length > 2048)
            {
                isAllowedToOpenBrowser = false;
            }
            else
            {
                isAllowedToOpenBrowser = true;
            }

            return isAllowedToOpenBrowser;
        }

        private bool CanAddGroupAND(object commandArg)
        {
            return true;
        }

        private bool CanAddGroupOR(object commandArg)
        {
            return true;
        }


        /// <summary>
        /// Retrieve the selected Entity's metadata
        /// </summary>
        /// <param name="EntityLogicalName"></param>
        private void ProcessSelectedEntityMetaData(String EntityLogicalName)
        {
            AsyncCallback asyncCallback = new AsyncCallback(result =>
            {
                Action method = () =>
                {
                    Entity = _dataProvider.RetrieveEntityAsyncCallback(result);
                    this.IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);
            });

            this.IsBusy = true;
            _dataProvider.RetrieveEntity(EntityLogicalName, true, asyncCallback);

        }



        #region Entity Properties
        /// <summary>
        /// The selected entity
        /// </summary>
        public EntityClass Entity
        {
            get { return _entity; }
            private set
            {
                _entity = value;

                if (_entity != null)
                {
                    //                
                    // Handle Select All on attributes event
                    //
                    _entity.AllAttributesSelectedEvent += ((o, a) =>
                    {
                        foreach (var item in _entity.Attributes)
                        {
                            if (item.SchemaName != "(Select All)")
                                item.UpdateSelected = true;
                        }
                    });

                    //                
                    // Handle Select All on attributes event
                    //
                    _entity.AllAttributesUnSelectedEvent += ((o, a) =>
                    {
                        foreach (var item in _entity.Attributes)
                        {
                            if (item.SchemaName != "(Select All)")
                                item.UpdateSelected = false;
                        }
                    });

                    //                
                    // Handle Select All on attributes event
                    //
                    _entity.AnyAttributeUnSelectedEvent += ((o, a) =>
                    {
                        _entity.Attributes[0].UpdateSelected = false;

                    });

                }

                RaisePropertyChanged("Entity");
                RaisePropertyChanged("AttributeList");
                RaisePropertyChanged("SortByAttributesList");
                RaisePropertyChanged("FiltersList");
                RaisePropertyChanged("OneToMany_RelationshipList");
                RaisePropertyChanged("ManyToOne_RelationshipList");
                RaisePropertyChanged("ManyToMany_RelationshipList");

                GenerateODataQuery();
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public EntityClass SelectedEntity
        {
            get { return _selectedEntity; }
            set
            {
                _selectedEntity = value;

                ProcessSelectedEntityMetaData(_selectedEntity.LogicalName);

                GenerateODataQuery();

                GenerateCommand.RaiseCanExecuteChanged();
                RaisePropertyChanged("SelectedEntity");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<EntityClass> EntityList
        {
            get { return _entities; }
            private set
            {
                _entities = value;
                RaisePropertyChanged("EntityList");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<AttributeClass> AttributeList
        {
            get { return _entity.Attributes; }
            private set
            {
                _entity.Attributes = value;
                RaisePropertyChanged("AttributeList");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<AttributeClass> SortByAttributesList
        {
            get { return _entity.SortByAttributes; }
            private set
            {
                _entity.SortByAttributes = value;
                RaisePropertyChanged("SortByAttributesList");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<FilterClass> FiltersList
        {
            get { return _entity.Filters; }
            private set
            {
                _entity.Filters = value;
                RaisePropertyChanged("FiltersList");
            }
        }

        #endregion

        #region Relationship List Properties

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<RelationshipClass> OneToMany_RelationshipList
        {
            get { return _entity.Relationships_OneToMany; }
            private set
            {
                _entity.Relationships_OneToMany = value;
                RaisePropertyChanged("OneToMany_RelationshipList");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<RelationshipClass> ManyToOne_RelationshipList
        {
            get { return _entity.Relationships_ManyToOne; }
            private set
            {
                _entity.Relationships_ManyToOne = value;
                RaisePropertyChanged("ManyToOne_RelationshipList");
            }
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<RelationshipClass> ManyToMany_RelationshipList
        {
            get { return _entity.Relationships_ManyToMany; }
            private set
            {
                _entity.Relationships_ManyToMany = value;
                RaisePropertyChanged("ManyToMany_RelationshipList");
            }
        }

        #endregion

        #region Relationship Attribute Properties

        public RelationshipClass SelectedOneToManyRelationship
        {
            get { return _selectedOneToManyRelationship; }
            set
            {
                _selectedOneToManyRelationship = value;

                if (_selectedOneToManyRelationship != null)
                {
                    AsyncCallback asyncCallback = new AsyncCallback(result =>
                    {
                        Action method = () =>
                        {
                            _selectedOneToManyRelationship.Entity = _dataProvider.RetrieveEntityAsyncCallback(result);

                            //                
                            // Handle Select All on attributes event
                            //
                            if (_selectedOneToManyRelationship.Entity != null)
                            {
                                _selectedOneToManyRelationship.Entity.AllAttributesSelectedEvent += ((o, a) =>
                                {
                                    foreach (var item in _selectedOneToManyRelationship.Entity.Attributes)
                                    {
                                        if (item.SchemaName != "(Select All)")
                                            item.UpdateSelected = true;
                                    }
                                });


                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedOneToManyRelationship.Entity.AllAttributesUnSelectedEvent += ((o, a) =>
                                {
                                    foreach (var item in _selectedOneToManyRelationship.Entity.Attributes)
                                    {
                                        if (item.SchemaName != "(Select All)")
                                            item.UpdateSelected = false;
                                    }
                                });

                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedOneToManyRelationship.Entity.AnyAttributeUnSelectedEvent += ((o, a) =>
                                {
                                    _selectedOneToManyRelationship.Entity.Attributes[0].UpdateSelected = false;

                                });
                            }

                            RaisePropertyChanged("SelectedOneToManyRelationship");
                            RaisePropertyChanged("OneToMany_RelationshipAttributeList");

                        };

                        this.View.Dispatcher.BeginInvoke(method);
                    });

                    this._dataProvider.RetrieveEntity(_selectedOneToManyRelationship.EntityLogicalName, false, asyncCallback);
                }
            }
        }


        public ObservableCollection<AttributeClass> OneToMany_RelationshipAttributeList
        {
            get
            {
                if (_selectedOneToManyRelationship != null && _selectedOneToManyRelationship.Entity != null)
                    return _selectedOneToManyRelationship.Entity.Attributes;
                else
                    return null;
            }
            set
            {
                _selectedOneToManyRelationship.Entity.Attributes = value;
                RaisePropertyChanged("OneToMany_RelationshipAttributeList");
            }
        }

        public RelationshipClass SelectedManyToOneRelationship
        {
            get { return _selectedManyToOneRelationship; }
            set
            {
                _selectedManyToOneRelationship = value;

                if (_selectedManyToOneRelationship != null) // && _selectedManyToOneRelationship.Entity == null)
                {
                    AsyncCallback asyncCallback = new AsyncCallback(result =>
                    {
                        Action method = () =>
                        {
                            _selectedManyToOneRelationship.Entity = _dataProvider.RetrieveEntityAsyncCallback(result);

                            if (_selectedManyToOneRelationship.Entity != null)
                            {
                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedManyToOneRelationship.Entity.AllAttributesSelectedEvent += ((o, a) =>
                                {
                                    foreach (var item in _selectedManyToOneRelationship.Entity.Attributes)
                                    {
                                        if (item.SchemaName != "(Select All)")
                                            item.UpdateSelected = true;
                                    }
                                });

                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedManyToOneRelationship.Entity.AllAttributesUnSelectedEvent += ((o, a) =>
                                {
                                    foreach (var item in _selectedManyToOneRelationship.Entity.Attributes)
                                    {
                                        if (item.SchemaName != "(Select All)")
                                            item.UpdateSelected = false;
                                    }
                                });

                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedManyToOneRelationship.Entity.AnyAttributeUnSelectedEvent += ((o, a) =>
                                {
                                    _selectedManyToOneRelationship.Entity.Attributes[0].UpdateSelected = false;

                                });
                            }

                            RaisePropertyChanged("SelectedManyToOneRelationship");
                            RaisePropertyChanged("ManyToOne_RelationshipAttributeList");
                        };

                        this.View.Dispatcher.BeginInvoke(method);
                    });

                    _dataProvider.RetrieveEntity(_selectedManyToOneRelationship.EntityLogicalName, false, asyncCallback);
                }
            }
        }

        public ObservableCollection<AttributeClass> ManyToOne_RelationshipAttributeList
        {
            get
            {
                if (_selectedManyToOneRelationship != null && _selectedManyToOneRelationship.Entity != null)
                    return _selectedManyToOneRelationship.Entity.Attributes;
                else
                    return null;
            }
            set
            {
                _selectedManyToOneRelationship.Entity.Attributes = value;
                RaisePropertyChanged("ManyToOne_RelationshipAttributeList");
            }
        }

        public RelationshipClass SelectedManyToManyRelationship
        {
            get { return _selectedManyToManyRelationship; }
            set
            {
                _selectedManyToManyRelationship = value;

                if (_selectedManyToManyRelationship != null)
                {
                    AsyncCallback asyncCallback = new AsyncCallback(result =>
                    {
                        Action method = () =>
                        {
                            _selectedManyToManyRelationship.Entity = _dataProvider.RetrieveEntityAsyncCallback(result);

                            if (_selectedManyToManyRelationship.Entity != null)
                            {
                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedManyToManyRelationship.Entity.AllAttributesSelectedEvent += ((o, a) =>
                                {
                                    foreach (var item in _selectedManyToManyRelationship.Entity.Attributes)
                                    {
                                        if (item.SchemaName != "(Select All)")
                                            item.UpdateSelected = true;
                                    }
                                });

                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedManyToManyRelationship.Entity.AllAttributesUnSelectedEvent += ((o, a) =>
                                {
                                    foreach (var item in _selectedManyToManyRelationship.Entity.Attributes)
                                    {
                                        if (item.SchemaName != "(Select All)")
                                            item.UpdateSelected = false;
                                    }
                                });

                                //                
                                // Handle Select All on attributes event
                                //
                                _selectedManyToManyRelationship.Entity.AnyAttributeUnSelectedEvent += ((o, a) =>
                                {
                                    _selectedManyToManyRelationship.Entity.Attributes[0].UpdateSelected = false;

                                });
                            }

                            RaisePropertyChanged("SelectedManyToManyRelationship");
                            RaisePropertyChanged("ManyToMany_RelationshipAttributeList");
                        };

                        this.View.Dispatcher.BeginInvoke(method);
                    });
                    _dataProvider.RetrieveEntity(_selectedManyToManyRelationship.EntityLogicalName, false, asyncCallback);
                }

            }
        }

        public ObservableCollection<AttributeClass> ManyToMany_RelationshipAttributeList
        {
            get
            {
                if (_selectedManyToManyRelationship != null && _selectedManyToManyRelationship.Entity != null)
                    return _selectedManyToManyRelationship.Entity.Attributes;
                else
                    return null;
            }
            set
            {
                _selectedManyToManyRelationship.Entity.Attributes = value;
                RaisePropertyChanged("ManyToMany_RelationshipAttributeList");
            }
        }

        #endregion

        #region Sorting Properties

        public AttributeClass SelectedSortBy1Attribute
        {
            get { return _selectedSortBy1Attribute; }
            set { if (_selectedSortBy1Attribute != value) { _selectedSortBy1Attribute = value; RaisePropertyChanged("SelectedSortBy1Attribute"); } }
        }
        public AttributeClass SelectedSortBy2Attribute
        {
            get { return _selectedSortBy2Attribute; }
            set { if (_selectedSortBy2Attribute != value) { _selectedSortBy2Attribute = value; RaisePropertyChanged(" SelectedSortBy2Attribute"); } }
        }
        public SortDirection SortBy1Direction
        {
            get { return _sortBy1Direction; }
            set { if (_sortBy1Direction != value) { _sortBy1Direction = value; RaisePropertyChanged("SortBy1Direction"); } }
        }
        public SortDirection SortBy2Direction
        {
            get { return _sortBy2Direction; }
            set { if (_sortBy2Direction != value) { _sortBy2Direction = value; RaisePropertyChanged("SortBy2Direction"); } }
        }

        #endregion


        #region OData Properties




        public String ODataQuery
        {
            get { return this._ODataQuery; }
            set
            {
                if (_ODataQuery != value)
                {
                    _ODataQuery = value;

                    QueryLength = String.Format("Length: {0}/2048", _ODataQuery.Length);

                    ExecuteCommand.RaiseCanExecuteChanged();
                    OpenBrowserCommand.RaiseCanExecuteChanged();

                    RaisePropertyChanged("QueryLength");
                    RaisePropertyChanged("ODataQuery");
                }
            }
        }

        public String ODataQueryWithVariables
        {
            get { return this._ODataQueryWithVariables; }
            set
            {
                if (_ODataQueryWithVariables != value)
                {
                    _ODataQueryWithVariables = value;

                    RaisePropertyChanged("QueryLength");
                    RaisePropertyChanged("ODataQueryWithVariables");
                }
            }
        }


        public int? Top
        {
            get { return _top; }
            set
            {
                _top = value;
            }
        }
        public int? SkipNext
        {
            get { return _skipNext; }
            set
            {
                _skipNext = value;
            }
        }

        #endregion

        #region REST Execution

        private AtomRequestCreator RequestCreatorATOM;
        private JSONRequestCreator RequestCreatorJSON;

        private void DownloadRawContentATOM(String ServiceURL, String Query)
        {
            RequestCreatorATOM = new AtomRequestCreator();

            Uri currentURI = new Uri(Query, UriKind.RelativeOrAbsolute);
            WebRequest GETRequest = null;
            if (ClientScript.IsOnPremise())
            {
                GETRequest = RequestCreatorATOM.CreateGET(currentURI);
            }
            else
            {
                GETRequest = RequestCreatorATOM.CreateGETFWithBrowserHttp(currentURI);
            }

            AsyncCallback asyncCallback = (result =>
            {
                Action method = () =>
                {
                    try
                    {
                        WebResponse GETResponse = GETRequest.EndGetResponse(result);

                        StreamReader textResponseReader = new StreamReader(GETResponse.GetResponseStream());

                        ATOMResultXml.Append(textResponseReader.ReadToEnd());
                        ResultXml = "Successful";
                        RaisePropertyChanged("ResultXml");
                        RaisePropertyChanged("ATOMResultXml");
                    }
                    catch (WebException ex)
                    {
                        ATOMResultXml.Append(ex.Message + "\r\n");
                        ResultXml = "Unsuccessful";
                        RaisePropertyChanged("ResultXml");
                        RaisePropertyChanged("ATOMResultXml");
                    }
                    this.IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);

            });

            GETRequest.BeginGetResponse(asyncCallback, null);
        }



        private void DownloadRawContentJSON(String ServiceURL, String Query)
        {

            if (!ClientScript.IsOnPremise())
            {
                JSONResultXml.Append("The JSON execution test is not supported by this tool when hosted in an IFD or CRM Online environment.");
                RaisePropertyChanged("JSONResultXml");
                return;
            }


            RequestCreatorJSON = new JSONRequestCreator();

            Uri currentURI = new Uri(Query, UriKind.RelativeOrAbsolute);
            WebRequest GETRequest = RequestCreatorJSON.CreateGET(currentURI);

            AsyncCallback asyncCallback = (result =>
            {
                Action method = () =>
                {
                    try
                    {
                        WebResponse GETResponse = GETRequest.EndGetResponse(result);
                        //System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>> Headers = new System.Collections.Generic.List<System.Collections.Generic.KeyValuePair<string, string>>();
                        //foreach (var header in GETResponse.Headers)
                        //{
                        //    Headers.Add(new System.Collections.Generic.KeyValuePair<string, string>(header.ToString(), GETResponse.Headers[header.ToString()].ToString()));
                        //}

                        StreamReader textResponseReader = new StreamReader(GETResponse.GetResponseStream());
                        JSONResultXml.Append(textResponseReader.ReadToEnd());

                        ResultXml = "Successful";

                        RaisePropertyChanged("ResultXml");
                        RaisePropertyChanged("JSONResultXml");
                    }
                    catch (Exception ex)
                    {
                        JSONResultXml.Append(ex.Message + "\r\n");

                        ResultXml = "Unsuccessful";

                        RaisePropertyChanged("ResultXml");
                        RaisePropertyChanged("JSONResultXml");
                    }
                    this.IsBusy = false;
                };

                this.View.Dispatcher.BeginInvoke(method);
            });
            GETRequest.BeginGetResponse(asyncCallback, null);
        }



        public void ExecuteRESTServiceATOM(String Query)
        {

            DownloadRawContentATOM(ClientScript.GetServerUrl() + "xrmservices/2011/OrganizationData.svc", Query);

        }

        public void ExecuteRESTServiceJSON(String Query)
        {

            DownloadRawContentJSON(ClientScript.GetServerUrl() + "xrmservices/2011/OrganizationData.svc", Query);

        }


        #endregion






        /// <summary>
        /// Buils theREST Query String
        /// </summary>
        /// <returns></returns>
        private string BuildODataQuery()
        {
            // /AccountSet?$select=Name,Address1_PostalCode,account_primary_contact/FullName,contact_customer_accounts/FullName&$orderby=Name asc&$expand=account_primary_contact,contact_customer_accounts

            ODataBuilder queryBuilder = new ODataBuilder();

            string query = "/" + SelectedEntity.SchemaNameSet;

            // Process select attributes
            queryBuilder.ProcessSelectAttributesAndExpands(Entity);

            // Process order by attributes
            queryBuilder.ProcessOrderByAttributes(SelectedSortBy1Attribute, SortBy1Direction, SelectedSortBy2Attribute, SortBy2Direction);

            // Process Filters
            queryBuilder.ProcessFilters(Entity);

            query += "?" + queryBuilder.BuildQuery();

            return query;
        }


        private void GenerateODataQuery()
        {
            ResultXml = "";
            RaisePropertyChanged("ResultXml");

            if (SelectedEntity != null)
            {
                ODataQuery = String.Format("{0}{1}{2}", ClientScript.GetServerUrl(), "/xrmservices/2011/OrganizationData.svc", BuildODataQuery());


            }
        }

        /// <summary>
        /// Buils theREST Query String
        /// </summary>
        /// <returns></returns>
        private string BuildODataQueryWithVariables()
        {

            ODataBuilder queryBuilder = new ODataBuilder();

            string query = "/" + SelectedEntity.SchemaNameSet;

            // Process select attributes
            queryBuilder.ProcessSelectAttributesAndExpands(Entity);

            // Process order by attributes
            queryBuilder.ProcessOrderByAttributes(SelectedSortBy1Attribute, SortBy1Direction, SelectedSortBy2Attribute, SortBy2Direction);

            // Process Filters
            queryBuilder.ProcessFiltersWithVariables(Entity);

            query += "?" + queryBuilder.BuildQuery();

            return query;
        }



        private void GenerateCodeGeneratorScript()
        {
            CodeGeneratorScript.Clear();

            if (SelectedEntity != null)
            {

                ODataQueryWithVariables = BuildODataQueryWithVariables();

                // Process Filters
                CodeGenerator generator = new CodeGenerator();

                StringBuilder script = new StringBuilder();
                script.Append(generator.BuildFunctionStub(Entity) + "{" + (char)13 + (char)10);
                script.Append("var query = \"" + ODataQueryWithVariables + "\";" + (char)13 + (char)10);
                script.Append("ExecuteQuery(query);" + (char)13 + (char)10);
                script.Append("}" + (char)13 + (char)10 + (char)13 + (char)10);
                script.Append(generator.GetAJAXRESTScriptFunctionAsText());

                CodeGeneratorScript.Append(script);
            }

            RaisePropertyChanged("CodeGeneratorScript");

        }


        #region  DelegateCommands

        private void Generate(object commandArg)
        {
            //this.IsBusy = true;
            GenerateODataQuery();
            GenerateCodeGeneratorScript();
            //this.IsBusy = false;
        }


        private void Execute(object commandArg)
        {
            this.IsBusy = true;
            ATOMResultXml.Clear();
            JSONResultXml.Clear();
            ExecuteRESTServiceATOM(ODataQuery);
            ExecuteRESTServiceJSON(ODataQuery);
        }


        private void OpenBrowserWithQuery(object commandArg)
        {
            HtmlPage.Window.Navigate(new Uri(ODataQuery), "_blank");
        }


        private void AddGroupAND(object commandArg)
        {
            CreateFilterGroupFromSelectedFilters("AND");
        }


        private void AddGroupOR(object commandArg)
        {
            CreateFilterGroupFromSelectedFilters("OR");
        }



        private void CreateFilterGroupFromSelectedFilters(String GroupType)
        {
            System.Collections.Generic.List<FilterClass> group = null;

            // Make sure total selected is more then 1
            int count = 0;
            foreach (FilterClass item in FiltersList)
            {
                if (item.IsSelected)
                    count++;
            }

            if (count > 1)
            {
                System.Collections.Generic.List<FilterClass> listFilters = new System.Collections.Generic.List<FilterClass>();
                listFilters.AddRange(FiltersList);

                foreach (FilterClass item in listFilters)
                {
                    if (item.IsSelected)
                    {
                        item.IsSelected = false;
                        if (group == null)
                        {
                            item.IsPrimaryGroupAttribute = true;
                            group = new System.Collections.Generic.List<FilterClass>();
                        }

                        // Set filter as final group attribute if it is the last in the group to be added.
                        if (count == group.Count + 1)
                        {
                            item.IsFinalGroupAttribute = true;
                        }

                        item.GroupLogicalOperator = GroupType;
                        group.Add(item);

                        if (item.IsPrimaryGroupAttribute == false)
                        {
                            var indexOfPreviousItem = FiltersList.IndexOf(group[group.Count - 2]);
                            if (FiltersList.IndexOf(item) != (indexOfPreviousItem + 1))
                            {
                                // Need to work out how to remove and add item back, collection doesn't like it..
                                FiltersList.Remove(item);
                                FiltersList.Insert(indexOfPreviousItem + 1, item);
                            }
                        }
                    }
                }
                if (_entity.FilterGroups == null)
                    _entity.FilterGroups = new System.Collections.Generic.List<System.Collections.Generic.List<FilterClass>>();

                _entity.FilterGroups.Add(group);

                RaisePropertyChanged("FiltersList");

            }
        }


        #endregion

    }


}
